extern crate bitfield;
extern crate byteorder;
extern crate eui48;
mod packet_handler;
use eui48::MacAddress;
use pcap::Capture;
use regex::bytes::Regex;
use std::str;

/* protocol ids, LittleEndian */
const ETH_P_IPV6: usize = 0xDD86;
const ETH_P_IP: usize = 0x08;
const TCP: usize = 0x06;
const UDP: usize = 0x11;
const ETH_P_ARP: usize  = 0x0608;
const ETH_P_RARP: usize = 0x3580; 

fn build_ether() -> packet_handler::EtherHeader {
    packet_handler::EtherHeader {
        ether_dhost: (MacAddress::new([0; 6])).to_hex_string(),
        ether_shost: (MacAddress::new([0; 6])).to_hex_string(),
        ether_type: 0,
    }
}

#[derive(Debug, Clone)]
pub struct QryData {
    pub id: i32,
    pub time: f64,
    pub data: Option<Vec<u8>>,
    pub ether_header: packet_handler::EtherHeader,
    pub ipv4_header: Option<packet_handler::IpV4Header>,
    pub ipv6_header: Option<packet_handler::IpV6Header>,
    pub tcp_header: Option<packet_handler::TcpHeader>,
    pub udp_header: Option<packet_handler::UdpHeader>,
    pub arp_header: Option<packet_handler::ArpHeader 'a>,
    pub reg_res: Option<String>,
}

fn flag_carnage(re: &Regex, payload: &[u8]) -> Option<String> {
    let mut flags: String = String::new();
    for mat in re.find_iter(payload) {
        flags.push_str(std::str::from_utf8(mat.as_bytes()).unwrap());
    }
    match 0 < flags.len() {
        false => None,
        true => Some(flags),
    }
}

pub fn parse <'a>(parse_file: &std::path::Path, filter_str: &str) -> Vec<QryData> {
    let ether_init = build_ether();

    let mut me = QryData {
        id: 0,
        time: 0.0,
        data: None,
        ether_header: ether_init,
        ipv4_header: None::<packet_handler::IpV4Header>,
        ipv6_header: None::<packet_handler::IpV6Header>,
        tcp_header: None::<packet_handler::TcpHeader>,
        udp_header: None::<packet_handler::UdpHeader>,
        arp_header: None::<packet_handler::ArpHeader<'a>>,
        reg_res: None::<String>,
    };
    let mut v: Vec<QryData> = Vec::new();

    let mut cap = Capture::from_file(parse_file).unwrap();
    Capture::filter(&mut cap, &filter_str).unwrap();
    let re = Regex::new(r"(?:http|https):[[::punct::]]?").unwrap();
    while let Ok(packet) = cap.next() {
        me.time = (packet.header.ts.tv_usec as f64 / 1000000.0) + packet.header.ts.tv_sec as f64;
        me.data = Some(packet.data.to_vec());
        me.reg_res = flag_carnage(&re, packet.data);
        me.ether_header = packet_handler::ethernet_handler(packet.data);
        match me.ether_header.ether_type as usize {
            ETH_P_IP => {
                me.ipv6_header = None::<packet_handler::IpV6Header>;
                me.ipv4_header = Some(packet_handler::ip_handler(packet.data)).unwrap();
                match me.ipv4_header.unwrap().ip_protocol as usize {
                    TCP => {
                        me.tcp_header = Some(packet_handler::tcp_handler(
                            me.ipv4_header.unwrap().ip_ihl,
                            packet.data,
                        ))
                        .unwrap();
                        me.data = packet_handler::payload_handler(
                            me.ipv4_header.unwrap().ip_ihl,
                            me.tcp_header.unwrap().data_offset,
                            packet.data,
                        );
                    }
                    UDP => {
                        me.udp_header = Some(packet_handler::udp_handler(
                            me.ipv4_header.unwrap().ip_ihl,
                            packet.data,
                        ))
                        .unwrap();
                        me.data = packet_handler::payload_handler(
                            me.ipv4_header.unwrap().ip_ihl,
                            7,
                            packet.data,
                        );
                    }
                    _ => println!("network protocol not implemented"),
                }
            }
            ETH_P_IPV6 => {
                me.ipv4_header = None::<packet_handler::IpV4Header>;
                me.ipv6_header = Some(packet_handler::ipv6_handler(packet.data)).unwrap();
                match me.ipv6_header.unwrap().next_header as usize {
                    TCP => {
                        me.tcp_header = Some(packet_handler::tcp_handler(10, packet.data)).unwrap();
                        me.data = packet_handler::payload_handler(
                            10,
                            me.tcp_header.unwrap().data_offset,
                            packet.data,
                        );
                    }
                    UDP => {
                        me.udp_header = Some(packet_handler::udp_handler(10, packet.data)).unwrap();
                        me.data = packet_handler::payload_handler(10, 7, packet.data);
                    }
                    _ => println!("network protocol not implemented"),
                }
            }
            ETH_P_ARP | ETH_P_RARP => {
                me.arp_header = Some(packet_handler::arp_handler(packet.data)).unwrap();
            }
            _ => println!("network protocol not implemented"),
        }
        v.push(QryData {
            id: 0,
            time: me.time,
            data: me.data,
            ether_header: me.ether_header,
            ipv4_header: me.ipv4_header,
            ipv6_header: me.ipv6_header,
            tcp_header: me.tcp_header,
            udp_header: me.udp_header,
            arp_header: me.arp_header,
            reg_res: me.reg_res,
        });
    }
    v
}

pub fn parse_device(parse_device: &str, filter_str: &str, insert_max: &usize) -> Vec<QryData> {
    let ether_init = build_ether();

    let mut me = QryData {
        id: 0,
        time: 0.0,
        data: None,
        ether_header: ether_init,
        ipv4_header: None::<packet_handler::IpV4Header>,
        ipv6_header: None::<packet_handler::IpV6Header>,
        tcp_header: None::<packet_handler::TcpHeader>,
        udp_header: None::<packet_handler::UdpHeader>,
        arp_header: None::<packet_handler::ArpHeader>,
        reg_res: None::<String>,
    };
    let mut v: Vec<QryData> = Vec::new();
    let mut cap = Capture::from_device(parse_device).unwrap().open().unwrap();
    Capture::filter(&mut cap, &filter_str).unwrap();

    let re = Regex::new(r"(?:http|https):[[::punct::]]").unwrap();
    'parse: while let Ok(packet) = cap.next() {
        me.time = (packet.header.ts.tv_usec as f64 / 1000000.0) + packet.header.ts.tv_sec as f64;
        me.data = Some(packet.data.to_vec());
        me.reg_res = flag_carnage(&re, packet.data);
        me.ether_header = packet_handler::ethernet_handler(packet.data);
        match me.ether_header.ether_type as usize {
            ETH_P_IP => {
                me.ipv6_header = None::<packet_handler::IpV6Header>;
                me.ipv4_header = Some(packet_handler::ip_handler(packet.data)).unwrap();
                match me.ipv4_header.unwrap().ip_protocol as usize {
                    TCP => {
                        me.tcp_header = Some(packet_handler::tcp_handler(
                            me.ipv4_header.unwrap().ip_ihl,
                            packet.data,
                        ))
                        .unwrap();
                        me.data = packet_handler::payload_handler(
                            me.ipv4_header.unwrap().ip_ihl,
                            me.tcp_header.unwrap().data_offset,
                            packet.data,
                        );
                    }
                    UDP => {
                        me.udp_header = Some(packet_handler::udp_handler(
                            me.ipv4_header.unwrap().ip_ihl,
                            packet.data,
                        ))
                        .unwrap();
                        me.data = packet_handler::payload_handler(
                            me.ipv4_header.unwrap().ip_ihl,
                            7,
                            packet.data,
                        );
                    }
                    _ => println!("network protocol not implemented"),
                }
            }
            ETH_P_IPV6 => {
                me.ipv4_header = None::<packet_handler::IpV4Header>;
                me.ipv6_header = Some(packet_handler::ipv6_handler(packet.data)).unwrap();
                match me.ipv6_header.unwrap().next_header as usize {
                    TCP => {
                        me.tcp_header = Some(packet_handler::tcp_handler(10, packet.data)).unwrap();
                        me.data = packet_handler::payload_handler(
                            10,
                            me.tcp_header.unwrap().data_offset,
                            packet.data,
                        );
                    }
                    UDP => {
                        me.udp_header = Some(packet_handler::udp_handler(10, packet.data)).unwrap();
                        me.data = packet_handler::payload_handler(10, 7, packet.data);
                    }
                    _ => println!("network protocol not implemented"),
                }
            }
            _ => println!("network protocol not implemented"),
        }
        v.push(QryData {
            id: 0,
            time: me.time,
            data: me.data,
            ether_header: me.ether_header,
            ipv4_header: me.ipv4_header,
            ipv6_header: me.ipv6_header,
            tcp_header: me.tcp_header,
            udp_header: me.udp_header,
            arp_header: me.arp_header,
            reg_res: me.reg_res,
        });

        if &v.len() >= insert_max {
            break 'parse;
        }
    }
    v
}
